/** */
package com.smc.sys.filter;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;

import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists;
import com.smc.common.config.Global;
import com.smc.common.utils.SpringContextHolder;
import com.smc.common.utils.StringUtils;

import com.smc.sys.model.User;
import com.smc.sys.security.AppContext;
import com.smc.sys.utils.SysUtils;
import com.smc.sys.utils.UserUtils;

/**
 * @author zouqinghua
 * @date 2016年9月20日 下午8:13:43
 */
public class AuthenticateFilter implements Filter {

	private static Logger logger = LoggerFactory.getLogger(AuthenticateFilter.class);

	private static final String HTTP_HEADER_TOKEN = "token";
	public static final String HTTP_AUTHENTICATION = "Authorization";

	//private AuthorizeService authorizeService = SpringContextHolder.getBean(AuthorizeService.class);
	//private SsoHttpService ssoHttpService = SpringContextHolder.getBean(SsoHttpService.class);
	
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
			throws IOException, ServletException {
		Stopwatch stopwatch = Stopwatch.createStarted();
		
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) resp;
		String URI = request.getRequestURI();
		String requestTraceId = request.getHeader("X-Request-ID");
		String remoteIP = getRemoteIP(request);
		
		String token = null;
		
		String url = getUrl(request,50);
		JSONObject json = null;
		
		//response.setHeader("X-Frame-Options", "SAMEORIGIN");
		User user = null;
		try {
			if (request.getMethod().equals("OPTIONS")) {
				logger.info("Method = OPTIONS , URI = {}", URI);
				response.setStatus(HttpStatus.OK.value());
				return;
			}
			if (URI.equals("/favicon.ico")) {
				logger.info("public , URI = {}", URI);
				response.setStatus(HttpStatus.OK.value());
				return;
			}
			//token = SsoUtils.getTokenBySSO(request);
			if(StringUtils.isBlank(token)){
				//token = request.getHeader(SsoUtils.HTTP_SSO_Token);
			}
			if(StringUtils.isBlank(token)){
				token = request.getHeader(HTTP_HEADER_TOKEN);
			}
			logger.info("Auth ： url = {} , token = {}, method = {}" ,url,token,request.getMethod() );
			Boolean isValid = true;
			/*AuthorizeService authorizeService = SpringContextHolder.getBean(AuthorizeService.class);
			if(StringUtils.isNotBlank(token)){
			    user = authorizeService.getUserByToken(token);
			}
			if (!isPublic(URI)) {
				String checkPermissions = SysUtils.getCheckPermissions();
				if (SystemPermissionAspect.CHECKED_PERMISSION_YES.equals(checkPermissions)) {
					if(StringUtils.isNotBlank(token)){
					    if(user ==null ){
					        isValid = false;
					    }
					}else{
						isValid = false;
					}
				}
			}*/
			/*if (!isValid && !UserUtils.LOGIN_PATH.equalsIgnoreCase(URI)) { //未登录，跳转到登录
				String dispatchUrl = UserUtils.LOGIN_PATH;
				RequestDispatcher rd = request.getRequestDispatcher(dispatchUrl);
	            rd.forward(request, response);
	            return ;
			}*/
			if(user==null){
			    if(UserUtils.isSSOLogin()){
			        user = new User();
			    }else{
			        token = "local-test";
			        //user = authorizeService.getUserByToken(token);
			    }
			    user = new User(2L);
		        user.setName("系统");
		        user.setLoginName("system");
			}
			if(user!=null && StringUtils.isBlank(user.getToken())){
			    user.setToken(token);
			}
			AppContext.setUser(user); // 注入用户信息
			AppContext.setAppToken(token);
			AppContext.setAuthorization(token);
			
			AppContext.setTraceId(requestTraceId);
			AppContext.setRemoteIP(remoteIP);
			
			chain.doFilter(req, resp);
			setHeaderAccess(response);
			
		}catch (Exception e) {
			String requestUrl = request.getRequestURL()+"";
			if(StringUtils.isNotBlank(request.getQueryString())&& !"null".equalsIgnoreCase(request.getQueryString())  ){
				requestUrl += "?"+request.getQueryString();
			}
			logger.error("服务异常  token = {} , url = {} ,paramMap = {}, e = {}", token, requestUrl, json ==null?"":json.toJSONString(), e.getMessage());
		} finally {
			long millis = stopwatch.stop().elapsed(TimeUnit.MILLISECONDS);
			logger.info("HttpResponse url = {} , Authorization = {},user = {},耗时：{}毫秒" ,url,token,user,millis );
			checkTimeout(millis, json, request);
			AppContext.releaseAppResource(); // 请求结束,释放资源
		}
	}
	
	@SuppressWarnings("unchecked")
	private JSONObject getParamter(HttpServletRequest request){
		JSONObject json = new JSONObject();
		Map<String,String[]> paramMap = request.getParameterMap();
		if(paramMap!=null && ! paramMap.isEmpty()){
			for (String key : paramMap.keySet()) {
				if("password".equals(key)){
					json.put(key, "*****");
					continue; //不打印敏感信息
				}
				json.put(key, paramMap.get(key)[0]);
			}
		}
		return json;
	}
	
	private String getUrl(HttpServletRequest request,Integer len){
		String URI = request.getRequestURI();
		String url = URI;
		if(len == null){
			len = 50;
		}
		if(StringUtils.isNotBlank(request.getQueryString())&& !"null".equalsIgnoreCase(request.getQueryString())  ){
			String query = request.getQueryString();
			
			String s = (len>0 && query.length()>len)?(query.substring(0, len)+"..."):query;
			
			url +="?"+s;
		}
		return url;
	}
	private void checkTimeout(long millis,JSONObject json,HttpServletRequest request){
		try {
			String URI = request.getRequestURI();
			if(millis > 2000 && isApi(URI)){ //响应时间超过2s ,且为 API接口  ,发送钉钉报警
				if(json == null){
					json = getParamter(request);
				}
				
				String title = "服务Curriculum Service接口响应超时！";
				String content = "耗时： "+millis+"毫秒"
								+"</br>\n\t接口 url : "+ (URI +="?"+request.getQueryString())
								+"</br>\n\t参数 : "+ json.toJSONString()
								;
		    	//DingDingMessageUtils.sendMessageToDingDing(content ,title,request);
			}
		} catch (Exception e) {
			logger.error("检查响应时间异常 ",e);
		}
		
	}
	public Boolean isPublic(String uri) {
		Boolean flag = false;
		String publicUriStr = Global.getConfig("user.public.uri");
		List<String> publicUris = Lists.newArrayList(publicUriStr.split(","));
		if (CollectionUtils.isNotEmpty(publicUris)) {
			for (String u : publicUris) {
				if (uri.startsWith(u)) {
					flag = true;
					break;
				}
			}
		}
		if (!flag && (uri.equals("/") || uri.equals("/favicon.ico"))) {
			flag = true;
		}
		return flag;
	}
	
	private Boolean isApi(String uri) {
		Boolean flag = false;
		String uriStr = Global.getConfig("user.api.uri");
		List<String> uris = Lists.newArrayList(uriStr.split(","));
		if (CollectionUtils.isNotEmpty(uris)) {
			for (String u : uris) {
				if (uri.startsWith(u)) {
					flag = true;
					break;
				}
			}
		}
		if (!flag && (uri.equals("/") || uri.equals("/favicon.ico"))) {
			flag = true;
		}
		return flag;
	}

	@Override
	public void destroy() {

	}

	public void setHeaderAccess(HttpServletResponse response) {
		response.setHeader("X-Frame-Options", "SAMEORIGIN");
		response.setHeader("Access-Control-Allow-Origin", "*");
		response.setHeader("Access-Control-Allow-Credentials", "true");
		response.setHeader("Access-Control-Allow-Headers",
				"X-Requested-With, content-type, accept, origin, authorization, x-csrftoken");
		response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
	}
	
	public String getRemoteIP(HttpServletRequest request) {
		String remoteIP = "";
		if (null != request) {
			remoteIP = request.getHeader("http_x_forwarded_for");
			if (StringUtils.isBlank(remoteIP)) {
				remoteIP = request.getHeader("x-forwarded-for");
			}
		}
		return remoteIP;
	}
}
